package com.game.monitor;


import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.monitor.FileAlterationListener;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class FileMonitor extends FileAlterationListenerAdaptor implements CommandLineRunner, ApplicationListener<ContextRefreshedEvent> {
    private Logger log = LoggerFactory.getLogger(getClass());

    private FileAlterationMonitor monitor = new FileAlterationMonitor();

    private Map<String, FileLoader> fileLoaders = new HashMap<>();

    public Map<String, FileAlterationObserver> fileObserver = new HashMap<>();

    public Map<String, List<FileChangeListener>> fileChangeListenerMap = new HashMap<>();

    public void start() {
        this.log.info("文件监视器启动");
        try {
            this.monitor.start();
        } catch (Exception e) {
            this.log.warn("文件监视器启动s失败", e);
        }
    }

    public void addFileObserver(String fileName, FileLoader fileLoader, boolean load) {
        if (fileName == null || fileName.isEmpty()) {
            return;
        }
        String[] fn = fileName.split("/");
        if (fn.length != 2) {
            return;
        }
        String dirName = fn[0];
        String fName = fn[1];
        addDirectoryObserver(dirName, null);
        if (fileLoader != null)
            this.fileLoaders.put(fName, fileLoader);
        if (load)
            onFileChange(new File(fileName));
    }

    public void addDirectoryObserver(String dirName, FileLoader fileLoader) {
        if (!this.fileObserver.containsKey(dirName)) {
            this.log.info("{},load={}", dirName);
            File file = new File(dirName);
            FileAlterationObserver observer = new FileAlterationObserver(file);
            observer.addListener((FileAlterationListener)this);
            try {
                observer.initialize();
            } catch (Exception e) {
                e.printStackTrace();
            }
            this.monitor.addObserver(observer);
            this.fileObserver.putIfAbsent(dirName, observer);
            if (fileLoader != null)
                this.fileLoaders.putIfAbsent(dirName, fileLoader);
        }
    }

    public void onFileChange(File file) {
        try {
            String fileName = file.getName();
                    FileLoader fileListener = this.fileLoaders.get(fileName);
            if (fileListener != null) {
                fileListener.load(file, false);
            } else {
                String path = file.getPath();
                this.fileLoaders.forEach((key, value) -> {
                    if (path.contains(key))
                        value.load(file, false);
                });
            }
            List<FileChangeListener> fileChangeListeners = this.fileChangeListenerMap.get(fileName);
            if (fileChangeListeners != null && !fileChangeListeners.isEmpty())
                for (FileChangeListener fcl : fileChangeListeners) {
                    try {
                        fcl.onChange(file);
                    } catch (Exception e) {
                    }
                }
        } catch (Exception e) {
        }
    }

    public void onFileCreate(File file) {
        try {
            String fileName = file.getName();
            if (fileName.startsWith("~"))
                return;
            this.log.info("============"+ fileName);
                    FileLoader fileListener = this.fileLoaders.get(fileName);
            if (fileListener != null) {
                fileListener.load(file, true);
            } else {
                String path = file.getPath();
                this.fileLoaders.forEach((key, value) -> {
                    if (path.contains(key))
                        value.load(file, false);
                });
            }
        } catch (Exception e) {
        }
    }

    public void onApplicationEvent(ContextRefreshedEvent event) {
                Map<String, FileChangeListener> maps = event.getApplicationContext().getBeansOfType(FileChangeListener.class);
        if (maps != null && !maps.isEmpty())
            maps.values().forEach(f -> {
                this.log.info(f.getFileName() + "->" + f.getClass());
                List<FileChangeListener> list = this.fileChangeListenerMap.get(f.getFileName());
                list.add(f);
            });
    }

    public void run(String... args) throws Exception {
        start();
    }
}
